/*
Copyright (C) 2008 raohmaru <http://www.raohmaru.com>

This file is part of Raohmaru AS3 Framework.

Raohmaru AS3 Framework is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Raohmaru AS3 Framework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Raohmaru AS3 Framework.  If not, see <http://www.gnu.org/licenses/>.
*/

package jp.raohmaru.utils
{

/**
 * Utilidades para el tratamiento de cadenas de texto.
 * @author raohmaru
 * @version 1.6
 */
public class StringUtil
{
	private static var UNICODE_CHARS	:Array = [ "Š", "Œ",  "Ž", "š", "œ",  "ž", "[ÀÁÂÃÄÅ]", 	"Æ",  "Ç", "[ÈÉÊË]", "[ÌÍÎÏ]",	"Ð", "Ñ", "[ÒÓÔÕÖØ]",	"[ÙÚÛÜ]",	"[ŸÝ]", "Þ",  "ß", "[àáâãäå]",	"æ",  "ç", "[èéêë]",	"[ìíîï]",	"ð", "ñ", "[òóôõöø]",	"[ùúûü]",	"[ýÿ]", "þ" ];
	private static var DECOMPOSED_CHARS	:Array = [ "S", "Oe", "Z", "s", "oe", "z", "A",			"Ae", "C", "E",		 "I",		"D", "N", "O",			"U",		"Y",	"Th", "ss", "a",		"ae", "c", "e",			"i",		"d", "n", "o",			"u",		"y",	"th" ]; 
	
	/**
	 * Especifica que la primera letra de cada palabra se convertirá en mayúscula (como en un titular).
	 * <i>"La Casa Gris Del Llano"</i>
	 */
	public static const TITLE : String = "title";
	/**
	 * Especifica que la primera letra de una sentencia, seperada por puntos, será mayúscula.
	 * <i>"Bajó del coche. Piso un charco. Maldijo."</i>
	 */
	public static const SENTENCE : String = "sentence";

	/**
	 * Devuelve una copia de esta cadena capitalizada según el tipo especificado (convierte la primera letra de una palabra en mayúscula, dado el caso).
	 * @param s Cadena de texto
	 * @param type Forma en que se capitalizará la cadena (por defecto sólo la primera letra)
	 * @return Una copia de esta cadena
	 * @example
	 * <listing version="3.0">
	 * import jp.raohmaru.utils.StringUtils;<br>	 * StringUtils.capitalize("En un agujero en el suelo, vivía un hobbit", StringUtil.TITLE);  // "En Un Agujero En El Suelo, Vivía Un Hobbit"	 * StringUtils.capitalize("empezó a contar: uno. dos. tres.", StringUtil.SENTENCE);  // "Empezó a contar: uno. Dos. Tres."</listing>
	 */
	public static function capitalize(str : String, type : String = null) : String
	{
		var arr : Array;

		switch(type)
		{
			case "title":		//"La Casa Gris Del Llano"
				arr = str.split(" ");
				arr.forEach(toUpperCaseFirstLetter);
				str = arr.join(" ");
				break;

			case "sentence":	//"Bajó del coche. Piso un charco. Maldijo."
				arr = str.split(". ");
				arr.forEach(toUpperCaseFirstLetter);
				str = arr.join(". ");
				break;

			default:			//"Torre en la montaña. disparos..."
				str = toUpperCaseFirstLetter(str);
		}

		return str;
	}

	/**
	 * Convierte en mayúscula la primera letra de la cadena y devuelve una copia. Utilizada en el método <code>Array.forEach</code> de la función <code>capitalize</code>
	 * @param str Cadena a modificar
	 * @return Cadena modificada
	 * @see #capitalize()
	 */
	public static function toUpperCaseFirstLetter(str:String, index:int=0, arr:Array=null) : String
	{
		str = str.replace( /([a-zA-ZàáäèéëìíïòóöùúüÀÁÄÈÉËÌÍÏÒÓÖÙÚÜ])/, function() : String
		{
			return arguments[1].toUpperCase();
		} );

		if(arr) arr[index] = str;

		return str;
	}

	/**
	 * Convierte un valor numérico en un cadena con el número de dígitos especificados, añadiendo "0" hasta llegar a la longitud deseada.
	 * @param number Número a convertir.
	 * @param num_digits Número de dígitos que tendrá la cadena resultante.
	 * @param suffix Indica si los nuevos dígitos se deben insertar antes (<code>false</code>) o después (<code>true</code>) del número.
	 * @return La cadena resultante
	 * @example
	 * <listing version="3.0">StringUtils.toDigits(4, 2);  // "04"</listing>
	 */
	public static function toDigits(number : Object, num_digits : int = 2, suffix :Boolean = false) : String
	{
		var str : String = number.toString();
		while(str.length < num_digits)
			str = (!suffix) ? "0" + str : str + "0";
		return str;
	}

	/**
	 * Devuelva una copia de la cadena con el orden invertido.
	 * @param str Cadena original
	 * @return Cadena invertida
	 */
	public static function reverse(str : String) : String
	{
		return str.split("").reverse().join("");
	}

	/**
	 * Elimina de la cadena los caracteres especificados, y devuelva una copia.<br>Por defecto elimina los espacios.
	 * @param str Cadena original
	 * @param char Matriz con los caracteres a eliminar
	 * @return Una cadena sin los caracteres especificados
	 */
	public static function trim(str : String, chars : Array = null) : String
	{
		if(!chars) chars = [" "];

		for(var i:int=0; i<chars.length; i++)
			str = str.split(chars [i]).join("");

		return str;
	}

    /**
     * Quita las etiquetas HTML de la cadena especificada y devuelve una nueva cadena sin formato HTML.
     * @param source Una cadena con etiquetas HTML
     * @return Una nueva cadena sin formato HTML
     * @source Basado en el método com.ericfeminella.utils.StringUtils.removeHTML() de Eric J. Feminella <http://www.newcommerce.ca/>
     */
    public static function removeHTML(source :String) :String
    {
        var pattern:RegExp = /<[^>]*>/g;
        return source.replace(pattern, "");
    }
    
    /**
     * Quita las etiquetas HTML pasadas como argumentos de la cadena especificada, y devuelve una nueva cadena sin esas etiquetas.
     * @param source Una cadena con etiquetas HTML.
     * @param args Las etiquetas HTML a eliminar, únicamente el nombre sin los corchetes '<>'.
     * @return Una nueva cadena sin las etiquetas HTML
	 * @example
	 * <listing version="3.0">
	 * import jp.raohmaru.utils.StringUtils;<br>
	 * var s :String = '<font size="36">¿Qué <br><B>HACEMOS</B>?</font>';
	 * StringUtil.removeHTMLTags(s, "font", "b");  // "¿Qué <br>HACEMOS?"</listing>
     */
    public static function removeHTMLTags(source :String, ...args :Array) :String
    {
    	var s :String = "";
    	for(var i:int=0; i<args.length; i++) 
    	{
    		if(i > 0) s += "|";
    		s += "(<(/|)"+args[i]+"(>|( [^>]*>)))";
    	}
    		
		var pattern:RegExp = new RegExp(s, "gi");
		return source.replace(pattern, "");
    }

	/**
	 * Reemplaza los caracteres HTML de una cadena por valores Unicode que sí puede renderizar correctamente Flash.
	 * También reemplaza las etiquetas <code>&lt;strong&gt;</code> y <code>&lt;em&gt;</code> por <code>&lt;b&gt;</code> e <code>&lt;i&gt;</code> respectivamente.
	 * @param str Cadena a analizar y reemplazar las ocurrencias.
	 * @return Una nueva cadena con los caracteres HTML reemplazados por valores Unicode.
	 */
	public static function parseHTML(str :String) : String
	{
		// Remplaza las etiquetas <strong> y <em> que dreamweaver utiliza en lugar de <b> y <i>
		str = str.replace(new RegExp("strong>", "g"), "b>").replace(new RegExp("em>", "g"), "i>");
		var regexp :RegExp,
			ent :XML,
			s :String;

		for each (ent in HTMLEntities.ENTITIES.entity)
		{
			s = "&"+ent.@code+";";
			regexp = new RegExp(s, "g");
			str = str.replace(regexp, ent);
			regexp = new RegExp(s.toUpperCase(), "g");
			str = str.replace(regexp, ent.toString().toUpperCase());
		}

		return str;
	}

	/**
	 * Elimina los saltos de carro "extra" de una cadena obtenida de un nodo de texto de un XML.
	 * Por alguna razón, Flash Player interpreta los saltos de carro en un nodo texto de XML como dobles.
	 * @param str Cadena con saltos de carro "extra" procedente de un XML.
	 * @return Una nueva cadena con los saltos de carro adicionales eliminados.
	 * @example
	 * <listing version="3.0">
	 var str :String = someXML.thenode.text();
	 trace(str);
	 // Lorem ipsum dolor sit amet,	 // 	 // consectetur adipiscing elit. Nam malesuada laoreet purus...	 // 	 // Nam malesuada laoreet purus...
	  
	 str = StringUtil.removeXMLNewLines(str)
	 trace(str);
	 // Lorem ipsum dolor sit amet, 
	 // consectetur adipiscing elit. Nam malesuada laoreet purus... 
	 // Nam malesuada laoreet purus...</listing>
	 */
	public static function removeXMLNewLines(str :String) : String
	{
		return str.replace(/\r/g, "");
		// Otro método
		//return unescape(escape(str).split("%0D%0A").join("%0A"));
	}
	
	/**
	 * Elimina todos los saltos de carro y nuevas líneas de una cadena de texto.
	 * @param str Cadena a procesar.
	 * @return Una nueva cadena sin saltos de carro ni caracteres de nueva línea.
	 */
	public static function removeBreakLines(str :String) : String
	{
		return unescape(escape(str).split("%0D%0A").join(""));
	}

	/**
	 * Procesa una cadena de texto, reemplazando los caracteres con acentos (y otros caracteres especiales) por sus homónimos no acentuados.
	 * La siguiente tabla muestra los caracteres que son reemplazados por el caracter de la columna de la derecha:
<table class="innertable" width="200">
<tr>
	<td>Š</td>
	<td width="40%">S</td>
</tr>
<tr>
	<td>Œ</td>
	<td>Oe</td>
</tr>
<tr>
	<td>Ž</td>
	<td>Z</td>
</tr>
<tr>
	<td>š</td>
	<td>s</td>
</tr>
<tr>
	<td>œ</td>
	<td>oe</td>
</tr>
<tr>
	<td>ž</td>
	<td>z</td>
</tr>
<tr>
	<td>ÀÁÂÃÄÅ</td>
	<td>A</td>
</tr>
 	<tr>
	<td>Æ</td>
	<td>Ae</td>
</tr>
<tr>
	<td>Ç</td>
	<td>C</td>
</tr>
<tr>
	<td>ÈÉÊË</td>
	<td>E</td>
</tr>
<tr>
	<td>ÌÍÎÏ</td>
	<td>I</td>
</tr>
	<tr>
	<td>Ð</td>
	<td>D</td>
</tr>
<tr>
	<td>Ñ</td>
	<td>N</td>
</tr>
<tr>
	<td>ÒÓÔÕÖØ</td>
	<td>O</td>
</tr>
	<tr>
	<td>ÙÚÛÜ</td>
	<td>U</td>
</tr>
	<tr>
	<td>ŸÝ</td>
	<td>Y</td>
</tr>
<tr>
	<td>Þ</td>
	<td>Th</td>
</tr>
<tr>
	<td>ß</td>
	<td>ss</td>
</tr>
<tr>
	<td>àáâãäå</td>
	<td>a</td>
</tr>
	<tr>
	<td>æ</td>
	<td>ae</td>
</tr>
<tr>
	<td>ç</td>
	<td>c</td>
</tr>
<tr>
	<td>èéêë</td>
	<td>e</td>
</tr>
	<tr>
	<td>ìíîï</td>
	<td>i</td>
</tr>
	<tr>
	<td>ð</td>
	<td>d</td>
</tr>
<tr>
	<td>ñ</td>
	<td>n</td>
</tr>
<tr>
	<td>òóôõöø</td>
	<td>o</td>
</tr>
	<tr>
	<td>ùúûü</td>
	<td>u</td>
</tr>
	<tr>
	<td>ýÿ</td>
	<td>y</td>
</tr>
<tr>
	<td>þ</td>
	<td>th</td>
</tr>
</table>
	 * @param str Cadena de texto
	 * @return Una cadena con los caracteres reemplazados.
	 * @source Basado en el siguiente artículo <http://stackoverflow.com/questions/587242/replacing-accents-w-their-counterparts-in-as3>
	 */		
	public static function decomposeUnicode(str :String) :String
	{
		var i :int = UNICODE_CHARS.length;
		
		while(--i > -1)
		{
			str = str.replace( new RegExp(UNICODE_CHARS[i], "g"), DECOMPOSED_CHARS[i]);
		}
		return str;
	}
}
}